#include <iostream>
#include <unistd.h>
#include <dirent.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <string>
#include <fstream>

#define ACCEPT_QUEUE_LENGTH 20
#define RCV_BUFFER_SIZE 10240
#define SEND_BUFFER_SIZE 10240
#define PATH_BUFFER_SIZE 10240
#define ROW_WIDTH 80

using namespace std;

int help(int socket_fd, char *buffer, const char *path);
int get(int socket_fd, char *buffer, const char *src, const char *path);
int put_post(int socket_fd, char *buffer, const char *dest, const char *path);
int dir(int socket_fd, char *buffer, const char *path);
int cd(int socket_fd, const char *dest, char *buffer, char *path);
int quit(int socket_fd);

int bad_cmd(int socket_fd, char *buffer, const char *path);
int send_reply(int socket_fd, const char *buffer, int size);
int get_relative_wd(const char *absolute, int size, char *cwd);

int init(int port);
void *accept_one_client(void *arg);
void *download(void *arg);
void *upload(void *arg);

struct file_transmit_arg
{
    char *file_name;
    int socket_fd;
};

char helpMSG[] = "Usage:\n\
    \thelp : print the help list\n\
    \tls : list files/directories in server's current work directory\n\
    \tcd <path> : change current work directory of server\n\
    \ttouch <path> : create file \n\
    \trm <path> : remove file \n\
    \tmkdir <path>: create dictionary\n\
    \trmdir <path>: remove dictionary\n\
    \tdownload <relative server file path>\n\
    \tdownload <relative server file path> <relative client dictionary path>\n\
    \tupload <relative client file path>\n\
    \tupload <relative client file path> <relative server dictionary path>\n\
    \tquit : quit this application";

int main()
{
    int listen_socket_fd = init(9221);
    if (listen_socket_fd < 0)
        return 1;

    listen(listen_socket_fd, ACCEPT_QUEUE_LENGTH);

    while (true)
    {
        int control_socket_fd = accept(listen_socket_fd, NULL, NULL);
        if (control_socket_fd < 0)
        {
            cout << "Accept client failed! Socket error!\n";
            continue;
        }

        pthread_t ntid;
        if (pthread_create(&ntid, NULL, accept_one_client, &control_socket_fd) != 0)
            cout << "Accept client failed! Create thread error!\n";
    }

    return 0;
}

int init(int port)
{
    int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
    int control_socket_opt = 1;
    setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &control_socket_opt, sizeof(control_socket_opt));
    if (listen_socket < 0)
    {
        cout << "Create socket failed!\n";
        return -1;
    }

    struct sockaddr_in control_sock_addr;
    memset(&control_sock_addr, 0, sizeof(control_sock_addr));
    control_sock_addr.sin_family = AF_INET;                // protocol family
    control_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); // set control socket address as local address
    control_sock_addr.sin_port = htons(port);              // set control socket port
    socklen_t length = sizeof(control_sock_addr);
    if (bind(listen_socket, (struct sockaddr *)&control_sock_addr, length) < 0)
    {
        cout << "Bind socket failed!\n";
        return -1;
    }

    if (getsockname(listen_socket, (struct sockaddr *)&control_sock_addr, &length) < 0)
    {
        cout << "Get socket name failed!\n";
        return -1;
    }

    cout << "ip address: " << inet_ntoa(control_sock_addr.sin_addr) << endl;

    cout << "Create socket at port " << ntohs(control_sock_addr.sin_port) << " success!\n";
    return listen_socket;
}


void Getfilepath(const char *path, const char *filename,  char *filepath)
{
    strcpy(filepath, path);
    if(filepath[strlen(path) - 1] != '/')
        strcat(filepath, "/");
    strcat(filepath, filename);
}
 
char* DeleteFile(const char* path)
{
    DIR *dir;
    struct dirent *dirinfo;
    struct stat statbuf;
    char *buffer;
    char filepath[256] = {0};
    lstat(path, &statbuf);
    
    if (S_ISREG(statbuf.st_mode))//判断是否是常规文件
    {
        remove(path);
    }
    else if (S_ISDIR(statbuf.st_mode))//判断是否是目录
    {
        if ((dir = opendir(path)) == NULL)
            buffer = (char *)"the directory does not exist";
        while ((dirinfo = readdir(dir)) != NULL)
        {
            Getfilepath(path, dirinfo->d_name, filepath);
            if (strcmp(dirinfo->d_name, ".") == 0 || strcmp(dirinfo->d_name, "..") == 0)//判断是否是特殊目录
            continue;
            DeleteFile(filepath);
            rmdir(filepath);
        }
        closedir(dir);
        buffer = (char *)"the directory has been deleted successfully!";
        
    }
    return buffer;
}

int makeFile(string name){
   FILE *fileP=NULL;
   fileP=fopen(name.c_str(),"w");
   fclose(fileP);
    return 0;
}


void *accept_one_client(void *arg)
{
    int control_socket_fd = *(int *)arg;
    cout << "Accept one client at " << control_socket_fd << " success!\n";

    bool _quit = false;
    char rcv_buffer[RCV_BUFFER_SIZE];
    char send_buffer[SEND_BUFFER_SIZE];
    char cur_absolute_path[PATH_BUFFER_SIZE];
    memset(cur_absolute_path, 0, PATH_BUFFER_SIZE);
    memset(send_buffer, 0, SEND_BUFFER_SIZE);
    memset(rcv_buffer, 0, RCV_BUFFER_SIZE);
    if (getcwd(cur_absolute_path, PATH_BUFFER_SIZE) == NULL)
    {
        cout << "Get current work directory failed!\n";
        return NULL;
    }

    // send help message
    if (help(control_socket_fd, send_buffer, cur_absolute_path) != 0)
        return NULL;

    while (!_quit)
    {
        memset(rcv_buffer, 0, sizeof(rcv_buffer));
        int rcv_bytes = read(control_socket_fd, rcv_buffer, sizeof(rcv_buffer));
        int errsv = errno;
        while (rcv_bytes <= 0 && errsv == EAGAIN && strlen(rcv_buffer) == 0)
        {
            rcv_bytes = read(control_socket_fd, rcv_buffer, sizeof(rcv_buffer));
            errsv = errno;
        }
        if (rcv_bytes > 0)
        {
            cout << "receive command : " << rcv_buffer << endl;

            bool has_space = false;
            int cmd_len = 0;
            for (int i = 0; i < strlen(rcv_buffer); i++)
            {
                if (rcv_buffer[i] == ' ' || rcv_buffer[i] == '\t')
                {
                    if (!has_space)
                    {
                        rcv_buffer[cmd_len] = ' ';
                        cmd_len++;
                        has_space = true;
                    }
                }
                else
                {
                    rcv_buffer[cmd_len] = rcv_buffer[i];
                    cmd_len++;
                    has_space = false;
                }
            }
            rcv_buffer[cmd_len] = '\0';

            char *cmd = strtok(rcv_buffer, " ");
            if (cmd == NULL)
            {
                if (bad_cmd(control_socket_fd, send_buffer, cur_absolute_path) != 0)
                {
                    cout << "Send error message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }

            memset(send_buffer, 0, SEND_BUFFER_SIZE);
            if (strcmp(cmd, "help") == 0)
            {
                if (help(control_socket_fd, send_buffer, cur_absolute_path) != 0)
                {
                    cout << "Send help message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }
            else if (strcmp(cmd, "ls") == 0)
            {
                if (dir(control_socket_fd, send_buffer, cur_absolute_path) != 0)
                {
                    cout << "Send dir message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }
            else if (strcmp(cmd, "cd") == 0)
            {
                char *dest = strtok(NULL, " ");
                if (dest == NULL)
                {
                    if (0 != bad_cmd(control_socket_fd, send_buffer, cur_absolute_path))
                    {
                        cout << "Send error message failed!\n";
                        close(control_socket_fd);
                        return NULL;
                    }
                }
                else
                {
                    if (0 != cd(control_socket_fd, dest, send_buffer, cur_absolute_path))
                    {
                        cout << "Send cd message failed!\n";
                        close(control_socket_fd);
                        return NULL;
                    }
                }
            }
            else if (strcmp(cmd, "quit") == 0)
            {
                quit(control_socket_fd);
                _quit = true;
            }
            else if (strcmp(cmd, "mkdir") == 0)
            {
                char *name = strtok(NULL, " ");
                string path = cur_absolute_path;
                path = path + "/" + name;
                char *buffer;

                if (opendir(path.c_str()) != NULL)
                {
                    buffer = (char *)"the directory already exists";
                }
                else if (mkdir(path.c_str(), 0777) == -1)
                {
                    buffer = (char *)"create directory failed";
                }
                else
                    buffer = (char *)"create directory success";

                send_reply(control_socket_fd, buffer, strlen(buffer));
            }
            // TDDO 文件夹的删除操作
            else if (strcmp(cmd, "rmdir") == 0)
            {
                char *name = strtok(NULL, " ");
                string path = cur_absolute_path;
                path = path + "/" + name;
                char *buffer;
                buffer=DeleteFile(path.data());
                rmdir(path.data());
                send_reply(control_socket_fd, buffer, strlen(buffer));
            }
            // TDDO 文件的创建操作
            else if (strcmp(cmd, "touch") == 0)
            {
                char *name = strtok(NULL, " ");
                string path = cur_absolute_path;
                path = path + "/" + name;
                char *buffer;

                if (access(path.c_str(), F_OK) != -1)
                {
                    buffer = (char *)"the file already exists";
                }
                else if (makeFile(path)!=0)
                {
                    buffer = (char *)"create file failed";
                }
                else
                    buffer = (char *)"create file success";

                send_reply(control_socket_fd, buffer, strlen(buffer));
                
            }
            // TDDO 文件的删除操作
            else if (strcmp(cmd, "rm") == 0)
            {
                char *name = strtok(NULL, " ");
                string path = cur_absolute_path;
                path = path + "/" + name;
                char *buffer;

                if (access(path.c_str(), F_OK) == -1)
                {
                    buffer = (char *)"the file does not exist";
                }
                else if (unlink(path.c_str()) == -1)
                {
                    buffer = (char *)"delete file failed";
                }
                else
                    buffer = (char *)"delete file successfully";

                send_reply(control_socket_fd, buffer, strlen(buffer));
            }
            else if (strcmp(cmd, "download") == 0)
            {
                char *src = strtok(NULL, " ");
                if (get(control_socket_fd, send_buffer, src, cur_absolute_path)!= 0)
                {
                    cout << "Send get message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }
            else if (strcmp(cmd, "upload") == 0)
            {
                char *src = strtok(NULL, " ");
                char *dest = strtok(NULL, " ");

                // if (opendir(dest) == NULL)
                // {
                //     char *buffer = (char *)"path is not found\n";
                //     send_reply(control_socket_fd, buffer, strlen(buffer));
                //     return NULL;
                // }

                usleep(50 * 1000);
                if (put_post(control_socket_fd, send_buffer, dest, cur_absolute_path)!= 0)
                {
                    cout << "Send get message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }
            else
            {
                if (bad_cmd(control_socket_fd, send_buffer, cur_absolute_path) != 0)
                {
                    cout << "Send error message failed!\n";
                    close(control_socket_fd);
                    return NULL;
                }
            }
        }
        else
        {
            cout << "Client at " << control_socket_fd << " lose...\n";
            close(control_socket_fd);
            return NULL;
        }
    }

    cout << "Client at " << control_socket_fd << " quit\n";
    return NULL;
}


int help(int socket_fd, char *buffer, const char *path)
{
    // send relative cwd
    if (0 != get_relative_wd(path, strlen(path), buffer))
        return -1;
    int cwd_len = strlen(buffer);
    // assume cwd_len < SEND_BUFFER_SIZE
    buffer[cwd_len] = '\n';
    strcat(buffer, helpMSG);
    return send_reply(socket_fd, buffer, strlen(buffer));
}

int send_reply(int socket_fd, const char *buffer, int size)
{
    if (buffer == NULL || size <= 0)
    {
        cout << "Bad message!\n";
        return -1;
    }
    int send_bytes = write(socket_fd, buffer, size);
    if (send_bytes <= 0)
    {
        // only try one time
        if (errno == EINTR)
            send_bytes = write(socket_fd, buffer, size);
        else
        {
            cout << "Send message error!\n";
            cout << "==================Message fail to send==================\n";
            cout << buffer << endl;
            cout << "==================Message fail to send==================\n";
            return -1;
        }
    }

    if (send_bytes != size)
        return 1;

    // cout << "send : " << buffer << endl;
    return 0;
}

int get_relative_wd(const char *absolute, int size, char *cwd)
{
    if (absolute == NULL || size <= 0)
    {
        cout << "Bad absolute path!\n";
        return 1;
    }
    int pos = -1;
    for (pos = size - 1; 0 <= pos; pos--)
        if (absolute[pos] == '/')
            break;
    // maybe cwd is '/'
    if (pos < 0)
    {
        cout << "Get cwd failed!\n";
        return 1;
    }

    if (strcmp(absolute, "/") == 0)
    {
        cwd[0] = '/';
    }
    else
    {
        for (int i = pos + 1; i < size; i++)
            cwd[i - pos - 1] = absolute[i];
    }
    return 0;
}

int quit(int socket_fd)
{
    close(socket_fd);
    return 0;
}

int dir(int socket_fd, char *buffer, const char *path)
{
    // send relative cwd
    if (0 != get_relative_wd(path, strlen(path), buffer))
        return -1;
    int cwd_len = strlen(buffer);
    // assume cwd_len < SEND_BUFFER_SIZE
    buffer[cwd_len] = '\n';

    int total_len = cwd_len + 1;

    // open cwd
    DIR *cwd = opendir(path);
    struct dirent *file_ent;
    // count file/directory number
    int count = 0;
    while ((file_ent = readdir(cwd)) != NULL)
        count++;
    closedir(cwd);

    char tmp_buf[PATH_BUFFER_SIZE];
    memset(tmp_buf, 0, PATH_BUFFER_SIZE);
    strcat(buffer, tmp_buf);
    total_len += strlen(tmp_buf);
    if (count > 0)
    {
        cwd = opendir(path);
        for (int i = 1; i <= count; i++)
        {
            file_ent = readdir(cwd);
            memset(tmp_buf, 0, PATH_BUFFER_SIZE);

            // test whether this item is a directory
            char tmp_path[PATH_BUFFER_SIZE];
            memset(tmp_path, 0, PATH_BUFFER_SIZE);
            sprintf(tmp_path, "%s/%s", path, file_ent->d_name);

            struct stat file_stat;
            int file_fd = open(tmp_path, O_RDONLY, S_IREAD);
            fstat(file_fd, &file_stat);

            if (S_ISDIR(file_stat.st_mode))
            {
                sprintf(tmp_buf, "dir\t%s\n", file_ent->d_name);
            }

            else
            {
                sprintf(tmp_buf, "file\t%s\n", file_ent->d_name);
            }

            if (total_len + strlen(tmp_buf) + 1 < SEND_BUFFER_SIZE)
            {
                strcat(buffer, tmp_buf);
                total_len += strlen(tmp_buf);
            }
            else
                break;
        }
        closedir(cwd);
    }

    return send_reply(socket_fd, buffer, strlen(buffer));
}

int cd(int socket_fd, const char *dest, char *buffer, char *path)
{
    const char *rcv_buffer = dest;

    int dir_len = strlen(rcv_buffer);

    char err_buf[128];
    memset(err_buf, 0, 128);

    if (rcv_buffer[0] == '/')
    { // cd to an absolute dir
        DIR *cwd = opendir(rcv_buffer);
        if (cwd == NULL)
        {
            int errsv = errno;
            switch (errsv)
            {
            case EACCES:
                strcat(err_buf, "Fail to open this directory, permission denied!");
                break;
            case ENOENT:
                strcat(err_buf, "Fail to open this directory, no such directory!");
                break;
            case ENOTDIR:
                strcat(err_buf, "Fail to open this directory, not a directory!");
                break;
            default:
                strcat(err_buf, "Fail to open this directory!");
            }
        }
        else
        {
            memset(path, 0, PATH_BUFFER_SIZE);
            strcpy(path, rcv_buffer);
            closedir(cwd);
        }
    }
    else
    { // cd to a relative dir
        int pos = 0;
        bool legal = true;
        while (pos < dir_len && legal)
        {
            char tmp_path[PATH_BUFFER_SIZE];
            memset(tmp_path, 0, PATH_BUFFER_SIZE);

            // parse one level
            for (int i = pos; i < dir_len; i++)
            {
                if (rcv_buffer[i] == '/')
                {
                    pos = i + 1;
                    break;
                }
                else
                    tmp_path[i - pos] = rcv_buffer[i];
                if (i == dir_len - 1)
                    pos = i + 1;
            }

            if (strlen(tmp_path) == 0)
                continue;

            if (strcmp(tmp_path, ".") == 0)
                continue;
            else
            {
                if (strcmp(tmp_path, "..") == 0)
                {
                    if (strcmp(path, "/") == 0)
                        continue;
                    int last_index = strlen(path) - 1;
                    while (0 <= last_index && path[last_index] != '/')
                        last_index--;
                    if (last_index == 0)
                        path[1] = '\0';
                    else
                        path[last_index] = '\0';
                }
                else
                {
                    char tmp_dir[PATH_BUFFER_SIZE];
                    memset(tmp_dir, 0, PATH_BUFFER_SIZE);
                    sprintf(tmp_dir, "%s/%s", path, tmp_path);
                    DIR *cwd = opendir(tmp_dir);
                    if (cwd == NULL)
                    {
                        int errsv = errno;
                        switch (errsv)
                        {
                        case EACCES:
                            strcat(err_buf, "Fail to open this directory, permission denied!");
                            break;
                        case ENOENT:
                            strcat(err_buf, "Fail to open this directory, no such directory!");
                            break;
                        case ENOTDIR:
                            strcat(err_buf, "Fail to open this directory, not a directory!");
                            break;
                        default:
                            strcat(err_buf, "Fail to open this directory!");
                        }
                        legal = false;
                    }
                    else
                    {
                        memset(path, 0, PATH_BUFFER_SIZE);
                        strcpy(path, tmp_dir);
                        closedir(cwd);
                    }
                }
            }
        }
    }

    // send relative cwd
    if (get_relative_wd(path, strlen(path), buffer) != 0)
        return -1;
    int cwd_len = strlen(buffer);
    buffer[cwd_len] = '\n';
    strcat(buffer, err_buf);
    return send_reply(socket_fd, buffer, strlen(buffer));
}

int bad_cmd(int socket_fd, char *buffer, const char *path)
{
    // send relative cwd
    if (0 != get_relative_wd(path, strlen(path), buffer))
        return -1;
    int cwd_len = strlen(buffer);
    // assume cwd_len < SEND_BUFFER_SIZE
    buffer[cwd_len] = '\n';
    strcat(buffer, "Bad command!\n");
    strcat(buffer, helpMSG);
    return send_reply(socket_fd, buffer, strlen(buffer));
}

int get(int socket_fd, char *buffer, const char *src, const char *path)
{

    pthread_t ntid;
    char file_name[PATH_BUFFER_SIZE];
    memset(file_name, 0, PATH_BUFFER_SIZE);
    sprintf(file_name, "%s/%s", path, src);
    cout<<"filenname: "<<file_name<<endl;
    bool begin = true;
    if (pthread_create(&ntid, NULL, download, (void *)file_name) != 0)
    {
        cout << "Get file failed! Create thread error!\n";
        begin = false;
    }

    // send relative cwd
    if (get_relative_wd(path, strlen(path), buffer)!= 0)
        return -1;
    int cwd_len = strlen(buffer);
    // assume cwd_len < SEND_BUFFER_SIZE
    buffer[cwd_len] = '\n';
    if (begin)
        strcat(buffer, "Begin get file");
    else
        strcat(buffer, "Fail to get file");
    strcat(buffer, src);
    return send_reply(socket_fd, buffer, strlen(buffer));
}

int put_post(int socket_fd, char *buffer, const char *dest, const char *path)
{
    char rcv_buffer[RCV_BUFFER_SIZE];
    memset(rcv_buffer, 0, sizeof(rcv_buffer));
    int rcv_bytes = read(socket_fd, rcv_buffer, sizeof(rcv_buffer));
    int errsv = errno;
    cout << "rcv bytes : " << rcv_bytes << endl;
    while (rcv_bytes <= 0 && errsv == EAGAIN && strlen(rcv_buffer) == 0)
    {
        rcv_bytes = read(socket_fd, rcv_buffer, sizeof(rcv_buffer));
        errsv = errno;
        cout << "rcv bytes : " << rcv_bytes << endl;
    }
    if (0 < rcv_bytes)
    {
        struct sockaddr_in data_sock_addr = *((sockaddr_in *)rcv_buffer);
        int file_transmit_socket = socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in peer_name;
        socklen_t namelen = sizeof(peer_name);
        if (getpeername(socket_fd, (struct sockaddr *)&peer_name, &namelen) != 0)
        {
            cout << "Get peer name failed!\n";
            return -1;
        }

        data_sock_addr.sin_addr.s_addr = peer_name.sin_addr.s_addr;

        cout << ntohs(data_sock_addr.sin_port) << " " << inet_ntoa(*(struct in_addr *)&data_sock_addr.sin_addr.s_addr) << endl;

        if (file_transmit_socket < 0)
        {
            cout << "Create socket failed!\n";
            return -1;
        }

        struct timeval max_wait_time;
        max_wait_time.tv_sec = 0;
        max_wait_time.tv_usec = 30 * 1000;
        if (setsockopt(file_transmit_socket, SOL_SOCKET, SO_RCVTIMEO, &max_wait_time, sizeof(max_wait_time)) != 0)
        {
            cout << "Set socket opt failed!\n";
            return -1;
        }
        if (connect(file_transmit_socket, (struct sockaddr *)&data_sock_addr, sizeof(struct sockaddr)) < 0)
        {
            cout << "Connect to server failed!\n";
            return -1;
        }

        cout << "Connect to client at 9222 success\n";

        char file_name[PATH_BUFFER_SIZE];
        memset(file_name, 0, PATH_BUFFER_SIZE);
        sprintf(file_name, "%s/%s", path, dest);
        ofstream fout;
        fout.open(file_name, ios_base::out | ios_base::binary);
        int errsv = errno;
        if (!fout.is_open())
        {
            if (errsv == EACCES)
            {
                // send relative cwd
                if (0 != get_relative_wd(path, strlen(path), buffer))
                    return -1;
                int cwd_len = strlen(buffer);
                // assume cwd_len < SEND_BUFFER_SIZE
                buffer[cwd_len] = '\n';
                strcat(buffer, "Error, permission denied!");
                return send_reply(socket_fd, buffer, strlen(buffer));
            }
        }
        else
            fout.close();

        bool begin = true;
        pthread_t ntid;
        file_transmit_arg my_arg;
        my_arg.file_name = file_name;
        my_arg.socket_fd = file_transmit_socket;
        if (pthread_create(&ntid, NULL, upload, (void *)&my_arg) != 0)
        {
            cout << "Put file failed! Create thread error!\n";
            begin = false;
        }

        // send relative cwd
        if (0 != get_relative_wd(path, strlen(path), buffer))
            return -1;
        int cwd_len = strlen(buffer);
        // assume cwd_len < SEND_BUFFER_SIZE
        buffer[cwd_len] = '\n';
        if (begin)
            strcat(buffer, "Begin put file ");
        else
            strcat(buffer, "Fail to put file ");
        strcat(buffer, dest);
        return send_reply(socket_fd, buffer, strlen(buffer));
    }
    else
        return -1;
}

void *download(void *arg)
{
    const char *src = (const char *)arg;
    int socket_fd = init(9222);

    listen(socket_fd, 1);
    int file_transmit_socket;

    // 尝试3次
    for (int i = 0; i < 3; i++)
    {
        file_transmit_socket = accept(socket_fd, NULL, NULL);
        if (file_transmit_socket >= 0)
            break;
    }

    // 还是连接失败的话， 那么就直接放弃了
    if (file_transmit_socket < 0)
    {
        cout << "Fail! Give up!\n";
        return NULL;
    }

    int src_file = open(src, O_RDONLY, S_IREAD);
    if (src_file >= 0)
    {
        char buffer[SEND_BUFFER_SIZE];
        memset(buffer, 0, SEND_BUFFER_SIZE);
        int bytes = read(src_file, buffer, SEND_BUFFER_SIZE);
        while (0 < bytes)
        {
            write(file_transmit_socket, buffer, bytes);
            cout << "Send " << bytes << " bytes\n";
            memset(buffer, 0, SEND_BUFFER_SIZE);
            bytes = read(src_file, buffer, SEND_BUFFER_SIZE);
        }
        cout << "Send finish\n";
        close(src_file);
    }
    else
    {
        cout << "Open file fail\n";
    }

    close(file_transmit_socket);
    close(socket_fd);
    cout << "Close socket at 9222\n";

    return NULL;
}

void *upload(void *arg)
{
    struct file_transmit_arg *myArg = (struct file_transmit_arg *)arg;
    const char *dest = myArg->file_name;
    int file_transmit_socket = myArg->socket_fd;

    if (file_transmit_socket > 0)
    {
        ofstream fout;
        cout << "put post file name " << dest << endl;
        fout.open(dest, ios_base::out | ios_base::binary);
        int errsv = errno;
        if (!fout)
        {
            cout << "Create file failed\n";
            cout << errsv << endl;
            return NULL;
        }
        char buffer[SEND_BUFFER_SIZE];
        memset(buffer, 0, SEND_BUFFER_SIZE);

        int bytes = read(file_transmit_socket, buffer, SEND_BUFFER_SIZE);

        errsv = errno;
        while (bytes <= 0 && errsv == EAGAIN && strlen(buffer) == 0)
        {
            bytes = read(file_transmit_socket, buffer, SEND_BUFFER_SIZE);
            errsv = errno;
            cout << "receive 2 " << bytes << " bytes\n";
        }
        cout << "receive 1 " << bytes << " bytes\n";
        bytes = strlen(buffer);
        while (bytes > 0)
        {
            fout << buffer;
            memset(buffer, 0, SEND_BUFFER_SIZE);
            bytes = read(file_transmit_socket, buffer, SEND_BUFFER_SIZE);
            errsv = errno;
            cout << "receive 2 " << bytes << " bytes\n";
        }
        close(file_transmit_socket);
        cout << "Close socket at 9223\n";
        fout.close();
    }
    else
        cout << "Fail! Give up!\n";
    cout << "Receive " << dest << " success!\n";
    return NULL;
}